﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace EcoSystem
{
    /// <summary>
    /// 处理Jobject类型的字典Json序列化问题
    /// </summary>
    public static class JObjectDictionaryExtenstions
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ParseJObjectDictonary(this Dictionary<string, object> dict)
        {
            return dict.ToDictionary(x => x.Key, x => ToCollections(x.Value));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        public static void ConvertJObjectDictonary(this object model)
        {
            var dictType = typeof(Dictionary<string, object>);
            if (model == null) { return; }
            var type = model.GetType();

            if (type == dictType)
            {
                //字典处理
                var dict = model as Dictionary<string, object>;
                foreach (string key in dict.Keys)
                {
                    dict[key] = ToCollections(dict[key]);
                }
                return;
            }
            else if ((type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) ||
                (type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(List<>)))
            {
                //List<T>类型处理或继承于List<T>的子类型
                var itemType = type.IsGenericType ? type.GetGenericArguments()[0] : type.BaseType.GetGenericArguments()[0];
                if (itemType.IsPrimitive ||
               itemType == typeof(string) ||
               itemType == typeof(DateTime) ||
               itemType == typeof(DateTimeOffset) ||
               itemType == typeof(TimeSpan) ||
               (itemType.IsGenericType && itemType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                {
                    return;
                }
                int count = Convert.ToInt32(type.GetProperty("Count").GetValue(model, null));
                var pItem = type.GetProperty("Item");
                for (int i = 0; i < count; i++)
                {
                    object item = pItem.GetValue(model, new object[] { i });
                    item?.ConvertJObjectDictonary();
                }
            }
            else if (type.IsPrimitive ||
                          type == typeof(string) ||
                          type == typeof(DateTime) ||
                          type == typeof(DateTimeOffset) ||
                          type == typeof(TimeSpan) ||
                          (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) ||
                          (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)))
            {
                //不需要做处理的类型
                return;
            }
            else
            {
                //其它有可能需要处理的类型
                var allItems = type.GetProperties(
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                allItems.Where(x => x.PropertyType.Equals(dictType)).ToList().ForEach(item =>
                {
                    var value = item.GetValue(model) as Dictionary<string, object>;
                    item.SetValue(model, value?.ParseJObjectDictonary());
                });
                var items = allItems.Where(x =>
                    !(x.PropertyType.IsPrimitive ||
                    type == typeof(string) ||
                    type == typeof(DateTime) ||
                    type == typeof(DateTimeOffset) ||
                    type == typeof(TimeSpan) ||
                    (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) ||
                    (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)))

                );
                foreach (var item in items)
                {
                    var pType = item.PropertyType;
                    if (pType.IsGenericType && pType == typeof(List<Dictionary<string, object>>))
                    {
                        var list = item.GetValue(model) as List<Dictionary<string, object>>;
                        if (list != null && list.Count > 0)
                        {
                            item.SetValue(model, list.Select(item => item.ParseJObjectDictonary()).ToList());
                        }
                    }
                    else
                    {
                        object value = item.GetValue(model);
                        value?.ConvertJObjectDictonary();
                    }
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static object ToCollections(this object o)
        {
            if (o is JObject jo) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value));
            if (o is JArray ja) return ja.ToObject<List<object>>().Select(ToCollections).ToList();
            return o;
        }

    }
}
